//+------------------------------------------------------------------+
//|                      ArrayObj.mqh 对象指针数组类头文件          |
//|                版权所有 2000-2025, MetaQuotes Ltd.              |
//|                        官方网址: https://www.mql5.com            |
//+------------------------------------------------------------------+
#include "Array.h"  // 引入基础数组类头文件，CArrayObj 继承自 CArray
//+------------------------------------------------------------------+
//| CArrayObj 类                                                     |
//| 功能：用于管理 CObject 及其派生类对象指针的动态数组类            |
//| 核心特性：支持对象指针的增删查改，提供「自动释放内存」开关，适配 MQL5 对象模型 |
//| 继承关系：派生自基础数组类 CArray，需结合 CObject 的 Compare/Save/Load 方法使用 |
//+------------------------------------------------------------------+
class CArrayObj : public CArray
  {
protected:
   CObject          *m_data[];           // 存储 CObject 及其派生类对象指针的核心数组
   bool              m_free_mode;        // 对象内存释放开关（true=自动删除动态分配的对象，false=仅移除指针不释放内存）

public:
   /**
    * @brief 构造函数：初始化 CArrayObj 类实例
    * @details 初始化数组容量、已存储元素数量，默认开启对象自动释放模式（m_free_mode = true）
    */
                     CArrayObj(void);

   /**
    * @brief 析构函数：销毁 CArrayObj 类实例
    * @details 调用 Shutdown 方法清空数组并释放所有动态分配的对象内存（根据 m_free_mode 配置）
    */
                    ~CArrayObj(void);

   //--- 受保护成员变量访问方法（对象内存管理模式）
   /**
    * @brief 获取当前对象内存释放模式
    * @return bool - 释放模式：true 表示自动删除动态分配的对象，false 表示仅移除指针不释放内存
    */
   bool              FreeMode(void) const { return(m_free_mode); }

   /**
    * @brief 设置对象内存释放模式（核心配置，需谨慎使用）
    * @param mode [in] 目标释放模式：
    *        - true：删除数组元素时，自动调用 delete 释放动态分配的 CObject 对象（避免内存泄漏）
    *        - false：仅从数组中移除对象指针，不释放对象内存（需外部手动管理，防止重复释放）
    */
   void              FreeMode(const bool mode) { m_free_mode=mode; }

   //--- 对象类型识别方法
   /**
    * @brief 获取当前数组对象的类型标识（自定义标识，区别于基础数据类型数组）
    * @return int - 类型标识，固定返回 0x7778（用于 runtime 类型判断）
    */
   virtual int       Type(void) const { return(0x7778); }

   //--- 文件操作相关方法（依赖 CObject 的 Save/Load 实现）
   /**
    * @brief 将数组中所有对象的序列化数据写入指定文件
    * @details 需确保数组中每个 CObject 派生类对象均正确实现 Save 方法
    * @param file_handle [in] 已打开的文件句柄（需提前通过 FileOpen 创建，权限包含写入）
    * @return bool - 操作结果：true 表示所有对象均写入成功，false 表示任一对象写入失败
    */
   virtual bool      Save(const int file_handle);

   /**
    * @brief 从指定文件读取数据并重建数组中的对象（依赖 CreateElement 方法）
    * @details 先清空数组，再通过 CreateElement 创建新对象，最后调用对象的 Load 方法加载数据
    * @param file_handle [in] 已打开的文件句柄（需提前通过 FileOpen 创建，权限包含读取）
    * @return bool - 操作结果：true 表示所有对象均读取并重建成功，false 表示创建/加载失败
    */
   virtual bool      Load(const int file_handle);

   //--- 数组元素创建方法（需派生类重写，用于 Load 时创建对象）
   /**
    * @brief 纯虚方法：在指定索引位置创建 CObject 派生类对象（需子类实现）
    * @details 基础 CArrayObj 类未实现，派生类需根据实际存储的对象类型重写（如 CArrayString 重写创建 CString 对象）
    * @param index [in] 要创建对象的数组索引
    * @return bool - 操作结果：true 表示对象创建成功并赋值到 m_data[index]，false 表示创建失败
    */
   virtual bool      CreateElement(const int index) { return(false); }

   //--- 动态内存管理方法（适配指针数组特性）
   /**
    * @brief 为数组预留指定大小的空闲内存空间（存储对象指针）
    * @details 检查当前剩余空闲空间，不足时按预设步长扩容，新扩容的位置初始化为 NULL 指针
    * @param size [in] 需要预留的空闲元素（指针）数量
    * @return bool - 操作结果：true 表示预留成功，false 表示 size≤0 或内存分配失败
    */
   bool              Reserve(const int size);

   /**
    * @brief 调整数组总容量（超出容量的对象按 m_free_mode 配置处理）
    * @param size [in] 调整后的数组总容量（存储对象指针的最大数量）
    * @return bool - 操作结果：true 表示容量调整成功，false 表示 size<0 或内存分配失败
    */
   bool              Resize(const int size);

   /**
    * @brief 彻底清空数组并释放所有资源（对象内存 + 数组内存）
    * @details 先调用 Clear 方法清空对象（根据 m_free_mode 释放内存），再释放数组本身的内存
    * @return bool - 操作结果：true 表示资源释放成功，false 表示数组内存释放失败
    */
   bool              Shutdown(void);

   //--- 数组填充相关方法（需确保指针有效性）
   /**
    * @brief 向数组末尾添加一个 CObject 派生类对象指针
    * @param element [in] 要添加的对象指针（需通过 CheckPointer 验证有效性，避免 NULL 或野指针）
    * @return bool - 操作结果：true 表示添加成功，false 表示指针无效或内存不足
    */
   bool              Add(CObject *element);

   /**
    * @brief 将另一个 CArrayObj 实例中的所有对象指针添加到当前数组末尾
    * @details 仅复制指针（浅拷贝），两个数组将共享同一批对象，需注意内存管理冲突
    * @param src [in] 指向源 CArrayObj 实例的指针（需通过 CheckPointer 验证有效性）
    * @return bool - 操作结果：true 表示所有指针添加成功，false 表示源指针无效或内存不足
    */
   bool              AddArray(const CArrayObj *src);

   /**
    * @brief 在数组指定索引位置插入一个 CObject 派生类对象指针
    * @details 插入位置及后续元素自动后移（指针数组重排），需确保插入后数组有序性（若为有序数组）
    * @param element [in] 要插入的对象指针（需通过 CheckPointer 验证有效性）
    * @param pos [in] 插入位置的索引（从 0 开始，需满足 0≤pos≤当前数组长度）
    * @return bool - 操作结果：true 表示插入成功，false 表示指针无效、位置无效或内存不足
    */
   bool              Insert(CObject *element,const int pos);

   /**
    * @brief 将另一个 CArrayObj 实例中的所有对象指针插入到当前数组指定位置
    * @details 仅复制指针（浅拷贝），插入后当前数组与源数组共享对象，需注意内存管理
    * @param src [in] 指向源 CArrayObj 实例的指针（需通过 CheckPointer 验证有效性）
    * @param pos [in] 插入位置的索引（从 0 开始，需满足 0≤pos≤当前数组长度）
    * @return bool - 操作结果：true 表示所有指针插入成功，false 表示源指针无效、位置无效或内存不足
    */
   bool              InsertArray(const CArrayObj *src,const int pos);

   /**
    * @brief 用另一个 CArrayObj 实例的内容覆盖当前数组（浅拷贝指针）
    * @details 先清空当前数组（根据 m_free_mode 释放原对象内存），再复制源数组的指针和排序状态
    * @param src [in] 指向源 CArrayObj 实例的指针（需通过 CheckPointer 验证有效性）
    * @return bool - 操作结果：true 表示覆盖成功，false 表示源指针无效或内存不足
    */
   bool              AssignArray(const CArrayObj *src);

   //--- 数组元素访问方法（返回对象指针，需外部验证有效性）
   /**
    * @brief 获取数组指定索引位置的 CObject 派生类对象指针
    * @param index [in] 要访问的元素索引（从 0 开始，需满足 0≤index<当前数组长度）
    * @return CObject* - 对应索引的对象指针；若索引无效，返回 NULL（需通过 CheckPointer 进一步判断指针类型）
    */
   CObject          *At(const int index) const;

   //--- 数组元素修改方法（涉及对象内存管理）
   /**
    * @brief 更新数组指定索引位置的对象指针（替换旧对象）
    * @details 若开启自动释放模式（m_free_mode=true），会先 delete 旧对象指针（仅动态分配的对象），再赋值新指针
    * @param index [in] 要更新的元素索引（需满足 0≤index<当前数组长度）
    * @param element [in] 新的对象指针（需通过 CheckPointer 验证有效性）
    * @return bool - 操作结果：true 表示更新成功，false 表示索引无效或新指针无效
    */
   bool              Update(const int index,CObject *element);

   /**
    * @brief 将数组指定索引的对象指针按偏移量移动位置
    * @param index [in] 要移动的对象指针原始索引（需在有效范围内）
    * @param shift [in] 偏移量（正数表示向后移动，负数表示向前移动，需确保移动后位置有效）
    * @return bool - 操作结果：true 表示移动成功，false 表示位置越界或偏移量为 0
    */
   bool              Shift(const int index,const int shift);

   //--- 数组元素删除方法（核心关注对象内存释放）
   /**
    * @brief 从数组中分离指定索引的对象指针（不释放对象内存）
    * @details 将目标指针从数组中移除（后续元素前移），返回该指针供外部继续使用
    * @param index [in] 要分离的元素索引（需满足 0≤index<当前数组长度）
    * @return CObject* - 分离出的对象指针；若索引无效，返回 NULL
    */
   CObject          *Detach(const int index);

   /**
    * @brief 删除数组指定索引的对象指针（根据 m_free_mode 决定是否释放对象内存）
    * @details 移除指针后，后续元素自动前移；若 m_free_mode=true，会 delete 动态分配的旧对象
    * @param index [in] 要删除的元素索引（需满足 0≤index<当前数组长度）
    * @return bool - 操作结果：true 表示删除成功，false 表示索引无效
    */
   bool              Delete(const int index);

   /**
    * @brief 删除数组中指定范围的对象指针（闭区间 [from, to]）
    * @details 移除指针后，后续元素自动前移；若 m_free_mode=true，批量 delete 范围内的动态对象
    * @param from [in] 删除范围的起始索引（需≥0）
    * @param to [in] 删除范围的结束索引（需≥from 且 < 当前数组长度）
    * @return bool - 操作结果：true 表示范围删除成功，false 表示范围无效
    */
   bool              DeleteRange(int from,int to);

   /**
    * @brief 清空数组中所有对象指针（保留数组内存，仅释放对象）
    * @details 若 m_free_mode=true，遍历数组 delete 所有动态分配的对象，再将所有指针设为 NULL；否则仅将指针设为 NULL
    */
   void              Clear(void);

   //--- 数组比较方法（依赖 CObject 的 Compare 实现）
   /**
    * @brief 比较当前数组与另一个 CArrayObj 实例是否“内容相等”
    * @details 需满足：1. 元素个数相同；2. 对应位置对象的 Compare 方法返回 0（表示对象内容相等）
    * @param array [in] 指向要比较的 CArrayObj 实例的指针（需通过 CheckPointer 验证有效性）
    * @return bool - 比较结果：true 表示数组内容完全相等，false 表示不相等（长度/对象内容不同）
    */
   bool              CompareArray(const CArrayObj *array) const;

   //--- 有序数组操作方法（依赖 CObject 的 Compare 实现排序/查找）
   /**
    * @brief 向有序数组中插入对象指针（保持数组有序性）
    * @details 需确保数组已排序（m_sort_mode≠-1），通过 CObject::Compare 方法确定插入位置
    * @param element [in] 要插入的对象指针（需通过 CheckPointer 验证有效性）
    * @return bool - 操作结果：true 表示插入成功且数组保持有序，false 表示数组未排序或指针无效
    */
   bool              InsertSort(CObject *element);

   /**
    * @brief 在有序数组中查找指定对象指针的索引（基于对象内容比较）
    * @details 通过 CObject::Compare 方法判断“相等”（返回 0），非指针地址比较
    * @param element [in] 要查找的对象指针（需通过 CheckPointer 验证有效性）
    * @return int - 查找结果：找到时返回对应索引，未找到/数组未排序/指针无效返回 -1
    */
   int               Search(const CObject *element) const;

   /**
    * @brief 在有序数组中查找第一个“大于”指定对象的元素索引
    * @details 基于 CObject::Compare 方法，当目标对象 Compare(当前对象) < 0 时判定为“大于”
    * @param element [in] 参考对象指针（需通过 CheckPointer 验证有效性）
    * @return int - 查找结果：找到时返回对应索引，未找到/数组未排序/指针无效返回 -1
    */
   int               SearchGreat(const CObject *element) const;

   /**
    * @brief 在有序数组中查找第一个“小于”指定对象的元素索引
    * @details 基于 CObject::Compare 方法，当目标对象 Compare(当前对象) > 0 时判定为“小于”
    * @param element [in] 参考对象指针（需通过 CheckPointer 验证有效性）
    * @return int - 查找结果：找到时返回对应索引，未找到/数组未排序/指针无效返回 -1
    */
   int               SearchLess(const CObject *element) const;

   /**
    * @brief 在有序数组中查找第一个“大于或等于”指定对象的元素索引
    * @details 基于 CObject::Compare 方法，当目标对象 Compare(当前对象) ≤ 0 时判定为“大于或等于”
    * @param element [in] 参考对象指针（需通过 CheckPointer 验证有效性）
    * @return int - 查找结果：找到时返回对应索引，未找到/数组未排序/指针无效返回 -1
    */
   int               SearchGreatOrEqual(const CObject *element) const;

   /**
    * @brief 在有序数组中查找第一个“小于或等于”指定对象的元素索引
    * @details 基于 CObject::Compare 方法，当目标对象 Compare(当前对象) ≥ 0 时判定为“小于或等于”
    * @param element [in] 参考对象指针（需通过 CheckPointer 验证有效性）
    * @return int - 查找结果：找到时返回对应索引，未找到/数组未排序/指针无效返回 -1
    */
   int               SearchLessOrEqual(const CObject *element) const;

   /**
    * @brief 在有序数组中查找指定对象第一次出现的索引（基于内容比较）
    * @param element [in] 要查找的对象指针（需通过 CheckPointer 验证有效性）
    * @return int - 查找结果：找到时返回第一次出现的索引，未找到/数组未排序/指针无效返回 -1
    */
   int               SearchFirst(const CObject *element) const;

   /**
    * @brief 在有序数组中查找指定对象最后一次出现的索引（基于内容比较）
    * @param element [in] 要查找的对象指针（需通过 CheckPointer 验证有效性）
    * @return int - 查找结果：找到时返回最后一次出现的索引，未找到/数组未排序/指针无效返回 -1
    */
   int               SearchLast(const CObject *element) const;

protected:
   /**
    * @brief 快速排序算法：对有序数组按对象内容排序（内部使用，依赖 CObject::Compare）
    * @param beg [in] 排序范围的起始索引（需≥0）
    * @param end [in] 排序范围的结束索引（需≥beg 且 < 当前数组容量）
    * @param mode [in] 排序模式（传递给 CObject::Compare 的第二个参数，可自定义排序规则）
    */
   void              QuickSort(int beg,int end,const int mode);

   /**
    * @brief 快速查找算法：在有序数组中定位对象的近似位置（内部使用，为 Search 系列提供支持）
    * @details 基于二分法，通过 CObject::Compare 方法判断对象大小关系
    * @param element [in] 要查找的对象指针（需通过 CheckPointer 验证有效性）
    * @return int - 查找的中间位置索引（不一定是匹配元素，需结合后续 Compare 验证）
    */
   int               QuickSearch(const CObject *element) const;

   /**
    * @brief 数组内部指针移动：将指定范围的对象指针从源位置复制到目标位置（内部使用）
    * @details 移动前会根据 m_free_mode 释放目标位置的旧对象内存，移动后将源位置指针设为 NULL
    * @param dest [in] 目标位置的起始索引（需≥0）
    * @param src [in] 源位置的起始索引（需≥0）
    * @param count [in] 要移动的指针个数（需满足 src + count ≤ 当前数组长度）
    * @return int - 操作结果：成功返回目标位置起始索引，失败返回 -1
    */
   int               MemMove(const int dest,const int src,int count);
  };
//+------------------------------------------------------------------+